﻿Imports ACompany.OrderProcessing.Infrastructure
Imports NHibernate

Public MustInherit Class BaseRepository(Of T As IAggregateRoot)
    Implements IRepository(Of T)

    Private _UnitOfWork As IUnitOfWork

    Public Sub Inject(ByVal UnitOfWork As Infrastructure.IUnitOfWork) Implements Infrastructure.IRepository(Of T).Inject
        _UnitOfWork = UnitOfWork
    End Sub

    Public Function FindAll() As System.Collections.Generic.IList(Of T) Implements Infrastructure.IRepository(Of T).FindAll

        Dim CriteriaQuery As NHibernate.ICriteria = SessionFactory.GetCurrentSession.CreateCriteria(GetType(T))
        Return CriteriaQuery.List(Of T)()

    End Function

    Public Function FindBy(ByVal Query As Infrastructure.Query) As System.Collections.Generic.IList(Of T) Implements Infrastructure.IRepository(Of T).FindBy

        Dim criteria As ICriteria = SessionFactory.GetCurrentSession.CreateCriteria(GetType(T))

        Return QueryTranslator.GetCriteriaFrom(criteria, Query).List(Of T)()
    End Function

    Public Function FindBy(ByVal Id As Guid) As T Implements Infrastructure.IRepository(Of T).FindBy

        ' Load doesn't return null if no entity found
        'Return NHSession.Load(Of T)(Id)

        Return SessionFactory.GetCurrentSession.Get(Of T)(Id)

    End Function

    Public Sub Remove(ByVal Entity As T) Implements Infrastructure.IRepository(Of T).Remove
        If _UnitOfWork Is Nothing Then

            Using Transaction = SessionFactory.GetCurrentSession.BeginTransaction

                SessionFactory.GetCurrentSession.Delete(Entity)
                Try
                    Transaction.Commit()
                Catch ex As Exception
                    Transaction.Rollback()
                    ' TODO: Log exception
                    Throw
                End Try                
            End Using

        Else
            _UnitOfWork.Delete(Entity)
        End If
    End Sub

    Public Sub Save(ByVal Entity As T) Implements Infrastructure.IRepository(Of T).Save
        If _UnitOfWork Is Nothing Then

            Using Transaction = SessionFactory.GetCurrentSession.BeginTransaction
                SessionFactory.GetCurrentSession.SaveOrUpdate(Entity)

                Try
                    Transaction.Commit()
                Catch ex As NHibernate.StaleObjectStateException
                    ' Catch StaleObjectStateException:
                    ' Entity was changed while we were viewing it, 
                    ' Wrap Nhibernate exception  and then send it 
                    ' back up the calling stack
                    Throw New ConcurrencyException(String.Format("Please reload the {0} as changes have been made to it since you have loaded it.", Entity.ToString), ex)
                Catch ex As Exception
                    Transaction.Rollback()
                    ' TODO: Log exception
                    Throw            
                End Try

            End Using

        Else
            _UnitOfWork.Save(Entity)
        End If
    End Sub
End Class
